package com.lnsoft.cac.client.test;

import com.lnsoft.cac.client.test.nettyClient.ClientReadHandler;
import com.lnsoft.cac.server.handle.codec.frameMessage.FrameFactory;
import com.lnsoft.cac.server.handle.codec.frameMessage.Util;
import com.lnsoft.cac.server.handle.codec.frameMessage.VoltageDayMon_Data;
import com.lnsoft.cac.server.handle.codec.frameMessage.VoltageDayMon_Msg;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;




//@Slf4j
/**
 * IDEA main 执行使用
 * 需要用到lombok插件
 */
//@SpringBootApplication
//@EnableScheduling
public class NettyClient {
    private static Logger logger = LoggerFactory.getLogger(NettyClient.class);

//    private static final String host = "10.192.34.104";//10.192.34.104
//    CAC测试
    private static final String host = "127.0.0.1";//10.192.34.104
//    private static final String host = "192.168.215.86";//10.192.34.104
    //    private static final int[] ports = new int[]{2501,2502,2503,2504,2505,2506,2507,2508,2509,2510};
    private static final int[] ports = new int[]{12001};

    public static final ExecutorService pools = Executors.newFixedThreadPool(10);


    private static int frameSerialNum = 0;

    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    //    public HashMap<String,long[]> timeList = new HashMap<>();
    public static long firstNodeHeartStartTime = 0;
    public static List<Integer> listHeartTime = new ArrayList<>();
    public static long firstNodeDataTime = 0;
    public static List<Integer> listDDataTime = new ArrayList<>();
    public static final Timer timer = new HashedWheelTimer();


    private static int getFrameSerialNum(){
        if (frameSerialNum < 255){
            frameSerialNum = (frameSerialNum + 1);
        }
        else {
            frameSerialNum = 0;
        }
        return frameSerialNum;
    }

    //发送心跳
    public static void sendHeartBeart() throws Exception{

        pools.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Iterator iter = channelGroup.iterator();
                    int clientFlag = 10000;
                    while (iter.hasNext()){
                        Channel channel = (Channel)iter.next();
                        String strClientId = "06M000000000" + Integer.toString(clientFlag);
                        channel.writeAndFlush(FrameFactory.heartSendFrame(strClientId.getBytes(), getFrameSerialNum()));
//                        logger.warn("心跳帧  >>>  发送完成");

//                        logger.info(strClientId);
                        if (strClientId.equals("06M00000000011100")) {
                            NettyClient.firstNodeHeartStartTime = System.currentTimeMillis();
                        }

                        clientFlag++;
                    }

                    heartBeatTimer();
                } catch (Exception e) {
                    logger.error("send heartBeat Exception: {}!!", e);
                }
            }
        });
    }

    //心跳定时器
    public static void heartBeatTimer() {
        timer.newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                sendHeartBeart();
            }
        }, 13, TimeUnit.SECONDS);
    }

    public static void sendDayStatisticsData() throws Exception{
        pools.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Iterator iter = channelGroup.iterator();
                    int clientFlag = 10000;
                    while (iter.hasNext()){
                        Channel channel = (Channel)iter.next();
                        String strClientId = "06M000000000" + Integer.toString(clientFlag);
                        //  监测帧--日统计数据报
                        VoltageDayMon_Msg vmMsgDay = new VoltageDayMon_Msg();
                        vmMsgDay.setMeasure_Point_ID(1);
                        vmMsgDay.setMeasureData_Num(1);
                        VoltageDayMon_Data vmDataDay = new VoltageDayMon_Data();
                        vmDataDay.setStat_Time(FrameFactory.currentTimeSeconds());
                        vmDataDay.setDQualified_rate(Util.rateValueToBytes("0.9999"));
                        vmDataDay.setDOvercap_rate(Util.rateValueToBytes("0.01"));
                        vmDataDay.setDUnderlower_rate(Util.rateValueToBytes("0.01"));
                        vmDataDay.setDStatistical_time(1000);
                        vmDataDay.setDQualified_time(999);
                        vmDataDay.setDOvercap_time(1);
                        vmDataDay.setDUnderlower_time(1);
                        vmDataDay.setDAverage_value(Util.voltageValueToBytes("123456.80"));
                        vmDataDay.setDMini_value(Util.voltageValueToBytes("123400.77"));
                        vmDataDay.setDMini_value_Time(FrameFactory.currentTimeSeconds());
                        vmDataDay.setDMax_value(Util.voltageValueToBytes("123497.55"));
                        vmDataDay.setDMax_value_time(FrameFactory.currentTimeSeconds());

                        List<VoltageDayMon_Data> listDay = new ArrayList<>();
                        listDay.add(vmDataDay);
                        vmMsgDay.setMeasureData(listDay);
                        channel.writeAndFlush(FrameFactory.vol_Day_SendFrame(strClientId.getBytes(),getFrameSerialNum(),vmMsgDay.toByteBuf()));
//                        logger.info("监测帧 -- 日统计报文 >>>  发送完成");

                        if (strClientId.equals("06M00000000011100")) {
                            NettyClient.firstNodeDataTime = System.currentTimeMillis();
                        }

                        clientFlag++;
                    }

                    dayStatisticsDataTimer();
                } catch (Exception e) {
                    logger.error("send data Exception: {}!!", e);
                }
            }
        });
    }

    public static void dayStatisticsDataTimer() {
        timer.newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                sendDayStatisticsData();
            }
        }, 19, TimeUnit.SECONDS);
    }

    public static void main(String[] args) throws Exception{
//        // 开启log4j2 异步模式 需要设置systemProperties
//        System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");
//
//        ApplicationContext context = SpringApplication.run(NettyClient.class, args);

//        Thread.sleep(3000);
//        logger.debug("spring boot 启动完毕,开始连接CAC....");


        EventLoopGroup group = new NioEventLoopGroup(20);
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(
                        new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                socketChannel.pipeline()
//                                        .addLast("IdleStateHandler",new IdleStateHandler(30,0,0))
//                                        .addLast("HeartBeatClientHandle",new HeartBeatClientHandle())
                                        .addLast(new ClientReadHandler());
                            }
                        }
                );
        //  发送心跳数据报文
        for(int i = 10000; i < 10002; i++){

            byte[] client = ("06M000000000" + Integer.toString(i)).getBytes();
            for(int port:ports){
                ChannelFuture cf = bootstrap.connect(host,port).sync();
                Channel channel = cf.channel();
                channelGroup.add(channel);
            }
        }

        //心跳定时发送
        heartBeatTimer();

        dayStatisticsDataTimer();

        while(true){
            Thread.sleep(600000);
        }
    }
}


//  心跳帧

//  监测帧--电压数据报
//                channel.writeAndFlush(FrameFactory.vol_SendFrame(client, getFrameSerialNum(),  FrameFactory.voltageMsg()));
//                log.info(MessageUtil.addColour("监测帧 -- 电压数据报文  >>>  发送完成"));


//                //  监测帧--月统计数据报
//                VoltageDayMon_Msg vmMsgMon = new VoltageDayMon_Msg();
//                vmMsgMon.setMeasure_Point_ID(1);
//                vmMsgMon.setMeasureData_Num(1);
//                VoltageDayMon_Data vmDataMon = new VoltageDayMon_Data();
//                vmDataMon.setStat_Time(FrameFactory.currentTimeSeconds());
//                vmDataMon.setDQualified_rate(Util.rateValueToBytes("0.9999"));
//                vmDataMon.setDOvercap_rate(Util.rateValueToBytes("0.01"));
//                vmDataMon.setDUnderlower_rate(Util.rateValueToBytes("0.01"));
//                vmDataMon.setDStatistical_time(1000);
//                vmDataMon.setDQualified_time(999);
//                vmDataMon.setDOvercap_time(1);
//                vmDataMon.setDUnderlower_time(1);
//                vmDataMon.setDAverage_value(Util.voltageValueToBytes("123456.80"));
//                vmDataMon.setDMini_value(Util.voltageValueToBytes("123400.77"));
//                vmDataMon.setDMini_value_Time(FrameFactory.currentTimeSeconds());
//                vmDataMon.setDMax_value(Util.voltageValueToBytes("123497.55"));
//                vmDataMon.setDMax_value_time(FrameFactory.currentTimeSeconds());
//
//                List<VoltageDayMon_Data> listMon = new ArrayList<>();
//                listMon.add(vmDataMon);
//                vmMsgMon.setMeasureData(listMon);
//                channel.writeAndFlush(FrameFactory.vol_Mon_SendFrame(client,getFrameSerialNum(),vmMsgMon.toByteBuf()));
//                log.info(MessageUtil.addColour("监测帧 -- 月统计报文 >>>  发送完成"));
